import { ActionContext } from "vuex";
import { RootState } from "../types";
import { MutationTypes as types } from "./mutation-types";
import { MutationTypes as playerTypes } from "../player/mutation-types";
import { SysActionTypes } from "./action-types";
import {
  openIndexedDB,
  DBAdd,
  DBGet,
  delIndexedDB,
  DBDel
} from "@/util/indexedDB";
import { OptionsType, OptionsDataType } from "@/const/indexedDB";
import { SysInfo, Version } from "./types";
import { Equipment, equiptoPackItem } from "@/const/equips/equipmentType";
import { DBRes } from "@/const/indexedDB";
import storage from "store";
import { PlayerActionTypes } from "../player/action-types";
import { WsDTO, wsUrl } from "@/const/ws";
import { tradeType as TradeType } from "@/const/trade";
export type Actions<S = RootState, R = any> = {
  [SysActionTypes.SYS_PUSH_INFO](
    { state, commit }: ActionContext<S, R>,
    data: SysInfo
  ): Promise<void>;
  [SysActionTypes.SYS_INIT]({
    state,
    dispatch,
    commit
  }: ActionContext<S, R>): Promise<void>;
  [SysActionTypes.SYS_ADD_EQUIP](
    { state, dispatch }: ActionContext<S, R>,
    data: Equipment
  ): Promise<Equipment>;
  [SysActionTypes.SYS_GET_EQUIP](
    { state, dispatch }: ActionContext<S, R>,
    data: OptionsDataType
  ): Promise<Equipment | undefined>;
  [SysActionTypes.SYS_DEL_EQUIP](
    { state, dispatch }: ActionContext<S, R>,
    data: OptionsDataType
  ): Promise<Equipment | undefined>;
  [SysActionTypes.SYS_GET_VERSION]({
    state,
    commit
  }: ActionContext<S, R>): Promise<void>;
  [SysActionTypes.SYS_SET_WS]({
    state,
    dispatch,
    commit
  }: ActionContext<S, R>): Promise<void>;
  [SysActionTypes.SYS_WS_SEND](
    { state, dispatch }: ActionContext<S, R>,
    data: WsDTO
  ): Promise<void>;
};

export const sysActions: Actions = {
  async [SysActionTypes.SYS_PUSH_INFO]({ state, commit }, payload) {
    const sysInfoList = state.sysInfo;
    sysInfoList.push(payload);
    if (sysInfoList.length > 500) {
      sysInfoList.shift();
    }
    commit(types.SET_SYS_INFO, sysInfoList);
  },
  async [SysActionTypes.SYS_INIT]({ state, dispatch, commit }) {
    // 连接数据库
    await dispatch(SysActionTypes.SYS_GET_VERSION);
    const { data, message } = await openIndexedDB();
    if (data) {
      commit(types.SET_SYS_DB, data);
    }
    dispatch(SysActionTypes.SYS_PUSH_INFO, new SysInfo(message, 3));
    // 获取存档装备
    commit(playerTypes.GET_PACKAGE);
    // 获取穿戴装备
    commit(playerTypes.GET_EQUIP);
    // 获取角色属性
    commit(playerTypes.GET_USER_PROPERTY);
    // 获取无尽之塔层数
    commit(playerTypes.GET_TOWER_LEVEL);
    if (state.userProperty.CHP <= 0) {
      dispatch(PlayerActionTypes.PLAYER_REVIVE);
    }
  },
  async [SysActionTypes.SYS_ADD_EQUIP]({ state, dispatch }, payload) {
    const option: OptionsType = {
      name: "equip",
      data: payload,
      permission: "readwrite"
    };
    const {
      code,
      data: { id },
      message
    }: DBRes = await DBAdd(state.indexedDB, option);
    if (code) {
      dispatch(SysActionTypes.SYS_PUSH_INFO, new SysInfo(message, 3));
    }
    const equipWithId: Equipment = {
      id,
      ...payload
    };
    return equipWithId;
  },
  async [SysActionTypes.SYS_GET_EQUIP]({ state, dispatch }, payload) {
    const option: OptionsType = {
      name: "equip",
      data: payload,
      permission: "readonly"
    };
    const { code, data, message }: DBRes = await DBGet(state.indexedDB, option);
    if (code) {
      dispatch(SysActionTypes.SYS_PUSH_INFO, new SysInfo(message, 3));
    }
    return data;
  },
  async [SysActionTypes.SYS_DEL_EQUIP]({ state, dispatch }, payload) {
    const option: OptionsType = {
      name: "equip",
      data: payload,
      permission: "readwrite"
    };
    const { code, data, message }: DBRes = await DBDel(state.indexedDB, option);
    if (code) {
      dispatch(SysActionTypes.SYS_PUSH_INFO, new SysInfo(message, 3));
    }
    return data;
  },
  async [SysActionTypes.SYS_GET_VERSION]({ state, commit }) {
    const currentVerison: Version = state.version;
    const storeVersion: Version = storage.get(types.SET_VERSION);
    const flagGameVersion = !(
      storeVersion && storeVersion.gameVersion === currentVerison.gameVersion
    );
    const flagDBVersion = !(
      storeVersion && storeVersion.dbVersion === currentVerison.dbVersion
    );
    if (flagDBVersion) await delIndexedDB();
    if (flagGameVersion) {
      localStorage.clear();
      window.location.reload();
    }
    if (flagDBVersion || flagGameVersion) {
      commit(types.SET_VERSION);
    }
  },
  async [SysActionTypes.SYS_SET_WS]({ state, dispatch, commit }) {
    state.ws = new WebSocket(wsUrl);
    state.ws.onerror = () => {
      dispatch(
        SysActionTypes.SYS_PUSH_INFO,
        new SysInfo("在线服务连接失败", 1)
      );
    };
    state.ws.onopen = () => {
      dispatch(
        SysActionTypes.SYS_PUSH_INFO,
        new SysInfo("在线服务连接成功", 3)
      );
      const firstLogin = {
        code: 0,
        data: new SysInfo(`${state.userInfo.userName}上线了`, 3),
        message: "上线了"
      };
      const data = new WsDTO(
        state.userInfo.userName,
        firstLogin,
        -1,
        0
      ).ObjectToString();
      state.ws.send(data);
      state.ws.onmessage = ({ data }: { data: any }) => {
        const decodeData = JSON.parse(data);
        if ([-1, 0, 1].includes(decodeData.imType)) {
          dispatch(SysActionTypes.SYS_PUSH_INFO, decodeData.body.data);
        } else if (decodeData.imType === -2) {
          state.onlinePlayers = decodeData.body.data;
        } else if (decodeData.imType === 2) {
          const { tradeType, money, equipments } = decodeData.body;
          if (tradeType === TradeType.GIVE) {
            let isMoney = "";
            if (money) {
              commit(playerTypes.MAKE_MONEY, money);
              isMoney = money + "金币";
            }
            if (equipments.length) {
              equipments.forEach(async (m: any) => {
                delete m.id;
                const data = await dispatch(SysActionTypes.SYS_ADD_EQUIP, m);
                commit(playerTypes.PUT_ITEM_TO_PACKAGE, equiptoPackItem(data));
              });
            }
            dispatch(
              SysActionTypes.SYS_PUSH_INFO,
              new SysInfo(
                `收到${decodeData.username}送来的${isMoney}`,
                2,
                equipments
              )
            );
          }
        } else if (decodeData.imType === -3) {
          const myId = decodeData.body.data;
          state.wsId = myId;
        }
      };
    };
  },
  async [SysActionTypes.SYS_WS_SEND]({ state }, payload) {
    if (state.ws) {
      state.ws.send(payload);
    }
  }
};
